[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Additions.Addition.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Additions.Addition.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Button.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Button.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.ExtenderDuplicator.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.ExtenderDuplicator.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.FieldConstraints.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.FieldConstraints.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Iframe.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Iframe.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.NodeBuilder.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.NodeBuilder.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Path.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Path.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Stylesheet.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Stylesheet.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Root.js", "application/x-javascript")]
[assembly: System.Web.UI.ScriptResource("BM.Tools.WebControls.MForm.Controls.Root.js", "BM.Tools.WebControls.MForm.Resources.MessageResource", "BM.Messages")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Root.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.CulturalContext.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.CulturalContext.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.MBasis.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.MBasis.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Validators.ValidationError.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Controls.Validators.ValidationError.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Resources.js.jquery.jquery.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Resources.js.jquery.jquery.debug.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Navigation.ItemsNavigator.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("BM.Tools.WebControls.MForm.Navigation.ItemsNavigator.debug.js", "application/x-javascript")]

namespace BM.Tools.WebControls.MForm.Controls
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;    
    using System.Web.UI;
    using System.Xml;
    using System.Xml.XPath;

    using AjaxControlToolkit;
  
    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Items;
    using BM.Tools.WebControls.MForm.Controls.Validators;
    using BM.Tools.WebControls.MForm.Design;
    using BM.Tools.WebControls.MForm.Generator;
    using BM.Tools.WebControls.MForm.Navigation;

    using Helper.EventValidation;

    /// <summary>
    /// A delegate of the method which will create the offspring's display name.
    /// </summary>
    /// <param name="sender">
    /// The sender.
    /// </param>
    /// <param name="args">
    /// The arguments.
    /// </param>
    /// <returns>
    /// the display name text.
    /// </returns>        
    public delegate string CreateDisplayName(Offspring sender, EventArgs args);

    /// <summary>
    /// The root control of the MForm control tree
    /// </summary>    
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.Button.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.MBasis.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.NodeBuilder.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.Path.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.Root.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.CulturalContext.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.Validators.ValidationError.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Resources.js.jquery.jquery.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Controls.Helper.RemovalButton.js")]
    [ClientScriptResource("BM.Tools.WebControls.MForm", "BM.Tools.WebControls.MForm.Navigation.ItemsNavigator.js")]
    [ToolboxData(@"<{0}:Root runat=""server"" ID="" ""  ></{0}:Root>")]
    [Designer(typeof(RootDesigner))]
    [ValidationProperty("Root")]
    public class Root : OffspringsOwner, IScriptControl
    {        
        public const string DefaultPrefix = "_def_";        

        private static string defaultImagePath = "Resources/MForm/Common/Images/";

        private string commonImagesPath = defaultImagePath;

        private CreateDisplayName displayNameMethod = DisplayNameHelper.DefaultDisplayName;

        private XmlNamespaceManager manager;

        private FormBuilderMode mode = FormBuilderMode.Edit;

        private Dictionary<string, ScriptComponentDescriptor> prototypeDescriptors = new Dictionary<string, ScriptComponentDescriptor>();

        private RootScriptHelper rootScriptHelper;                

        private RootValidator validator;        

        /// <summary>
        /// Initializes a new instance of the <see cref="Root"/> class. 
        /// </summary>
        public Root()
        {                        
            validator = new RootValidator(this);
            ContainerCssClass = "MFormContainer";
            CulturalContext = new CulturalContext();
            UriMappings = new UriMappings();
        }        

        /// <summary>
        /// Gets or sets the css class of the container div.
        /// </summary>
        [DefaultValue("MFormContainer")]
        public string ContainerCssClass
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the object that keeps MForm cultural settings.
        /// </summary>
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public CulturalContext CulturalContext
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets or sets the method of how to create the default display name method.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public CreateDisplayName DisplayNameMethod
        {
            get
            {
                return displayNameMethod;
            }

            set
            {
                displayNameMethod = value;
            }
        }

        /// <summary>
        /// Gets or sets the image path.
        /// </summary>        
        [ExtenderControlProperty]        
        public string CommonImagesPath
        {
            get
            {
                return commonImagesPath;
            }

            set
            {
                commonImagesPath = value;
            }
        }

        /// <summary>
        /// Gets or sets the namespace manager.
        /// </summary>        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public XmlNamespaceManager Manager
        {
            get
            {
                if (manager == null && UriMappings != null)
                {
                    Manager = UriMappings.ToManager();
                }

                return manager;
            }

            set
            {
                manager = new XmlNamespaceManager(new NameTable());                
                foreach (var pair in value.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml))
                {                    
                    manager.AddNamespace(pair.Key, pair.Value);
                }                

                manager.AddNamespace(DefaultPrefix, manager.DefaultNamespace);                
            }
        }

        /// <summary>
        /// Gets or sets the form builder mode.
        /// </summary>        
        [DefaultValue(FormBuilderMode.Edit)]
        public override FormBuilderMode Mode
        {
            get
            {
                return mode;
            }

            set
            {
                mode = value;
            }
        }

        /// <summary>
        /// Gets the output xml.
        /// </summary>        
        [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "Specific functionality provided by the concrete type is required")]
        public XmlDocument OutputXml
        {
            get
            {
                if (DocumentElementItem == null)
                {
                    return null;
                }

                return DocumentElementItem.GetOutputXml();
            }
        }

        /// <summary>
        /// Gets the output xml with left nodes.
        /// </summary>        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "Specific functionality provided by the concrete type is required")]
        public XmlDocument OutputXmlWithLeftNodes
        {
            get
            {
                if (DocumentElementItem == null)
                {
                    return null;
                }

                return DocumentElementItem.GetOutputXmlWithLeftNodes();
            }
        }

        /// <summary>
        /// Gets ParentBasis.
        /// </summary>        
        public override OffspringsOwner ParentBasis
        {
            get
            {
                return null;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether items in view mode should be validated.
        /// </summary>
        [DefaultValue(false)]
        public bool ShouldValidateInViewMode
        {
            get;
            set;
        }

        /// <summary>
        /// Gets UriMappings.
        /// </summary>        
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public UriMappings UriMappings
        {
            get;
            private set;            
        }

        /// <summary>
        /// Gets Validator.
        /// </summary>        
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public RootValidator Validator
        {
            get
            {
                return validator;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the Root is during generation.
        /// </summary>
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This code is invoked internally by the designer")]
        internal bool IsDuringGeneration
        {
            get; 
            set;
        }

        /// <summary>
        /// Gets LeftNodesDictionary.
        /// </summary>      
        internal Dictionary<string, Collection<XPathNavigator>> LeftNodesDictionary
        {
            get
            {
                EnsureChildControls();
                if (Page.Session[UniqueID + "_LeftNodes"] == null)
                {
                    Page.Session[UniqueID + "_LeftNodes"] = new Dictionary<string, Collection<XPathNavigator>>();
                }

                return Page.Session[UniqueID + "_LeftNodes"] as Dictionary<string, Collection<XPathNavigator>>;
            }
        }

        internal Dictionary<string, ScriptComponentDescriptor> PrototypeDescriptors
        {
            get
            {
                return prototypeDescriptors;
            }
        }

        /// <summary>
        /// Gets XPathString.
        /// </summary>
        /// <value>
        /// The x path string.
        /// </value>
        internal override string XPathString
        {
            get
            {
                return ".";
            }
        }

        /// <summary>
        /// Gets RootScriptHelper.
        /// </summary>
        /// <value>
        /// The root script helper.
        /// </value>
        protected RootScriptHelper RootScriptHelper
        {
            get
            {
                if (rootScriptHelper == null)
                {
                    rootScriptHelper = new RootScriptHelper(this);
                }

                return rootScriptHelper;
            }
        }

        /// <summary>
        /// Gets DocumentElementItem.
        /// </summary>
        /// <value>
        /// The document element item.
        /// </value>
        private OffspringItem DocumentElementItem
        {
            get
            {
                if (Items.Count == 0)
                {
                    return null;
                }

                var rootItem = Items[0] as RootItem;
                return rootItem.ChildItems.FirstOrDefault();
            }
        }

        /// <summary>
        /// Selects offspring item ancestors, matching the path query
        /// </summary>
        /// <param name="path">
        /// The xpath-like path.
        /// </param>
        /// <returns>
        /// the collection of <see cref="OffspringItem" /> objects.
        /// </returns>
        public IEnumerable<OffspringItem> Select(string path)
        {
            if (Items.Count == 0)
            {
                return null;
            }

            var navigator = new OffspringsNavigator(Items[0], path);
            return navigator.Select();
        }

        /// <summary>
        /// Selects the first matching offspring item ancestor, matching the path query
        /// </summary>
        /// <param name="path">
        /// The xpath-like path.
        /// </param>
        /// <returns>
        /// the <see cref="OffspringItem" /> object or null.
        /// </returns>
        public OffspringItem SelectSingle(string path)
        {
            if (Items.Count == 0)
            {
                return null;
            }

            var navigator = new OffspringsNavigator(Items[0], path);
            return navigator.SelectSingle();
        }

        /// <summary>
        /// gets script descriptors
        /// </summary>
        /// <returns>
        /// the script descriptors
        /// </returns>
        public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            return RootScriptHelper.GetScriptDescriptors();
        }

        /// <summary>
        /// The method is not used.
        /// </summary>
        /// <returns>
        /// returns null
        /// </returns>
        public IEnumerable<ScriptReference> GetScriptReferences()
        {
            return null;
        }

        /// <summary>
        /// Creates child controls and adds optional items container and the default validator
        /// </summary>
        /// <param name="dataBind">
        /// Should perform a databinding on children
        /// </param>
        protected override void CreateChildControls(bool dataBind)
        {
            base.CreateChildControls(dataBind);            
            Controls.Add(Validator);            
        }

        /// <summary>        
        /// Creates an <see cref="RootItem" /> object from this object's definitions.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="navigator">
        /// The navigator.
        /// </param>
        /// <returns>
        /// the <see cref="RootItem"/> object
        /// </returns>
        protected override OffspringItem CreateItem(int index, XPathNavigator navigator)
        {
            return new RootItem(this, index, navigator);
        }

        /// <summary>
        /// Registers associated embedded resources.
        /// </summary>
        /// <param name="e">
        /// The event args.
        /// </param>
        protected override void OnPreRender(EventArgs e)
        {
            RootScriptHelper.RegisterScripts();                        
            base.OnPreRender(e);            
        }

        /// <summary>
        /// Renders the control.
        /// </summary>
        /// <param name="writer">
        /// The writer.
        /// </param>
        protected override void Render(HtmlTextWriter writer)
        {
            var eventValidationHelper = new EventValidationHelper(this);
            eventValidationHelper.Register();
            RootScriptHelper.Render();

            writer.Write("<div id=\"{0}\" class=\"{1}\">", ClientID, ContainerCssClass);
            RenderChildren(writer);
            writer.Write("</div>");
        }

        /// <summary>
        /// Renders the children controls.
        /// </summary>
        /// <param name="writer">
        /// The writer.
        /// </param>
        protected override void RenderChildren(HtmlTextWriter writer)
        {
            if (DesignMode)
            {
                EnsureChildControls();
            }

            if (Validator.Placement == ValidatorPlacement.BeforeContent)
            {
                Validator.RenderControl(writer);
            }

            HiddenInput.RenderControl(writer);
            if (Items.Count > 0)
            {
                foreach (Control c in Items)
                {
                    c.RenderControl(writer);
                }
            }

            if (Validator.Placement == ValidatorPlacement.AfterContent)
            {
                Validator.RenderControl(writer);
            }                      
        }

        /// <summary>
        /// Removes all data that is created when child items are created
        /// </summary>
        protected override void ResetChildControls()
        {
            base.ResetChildControls();            
            prototypeDescriptors = new Dictionary<string, ScriptComponentDescriptor>();
        }

        private void ResetCommonImagesPath()
        {
            CommonImagesPath = defaultImagePath;
        }

        private bool ShouldSerializeCommonImagesPath()
        {
            return CommonImagesPath != defaultImagePath;
        }        
    }
}